package accounts

import (
	"bufio"
	"bytes"
	"core"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/ethereum/go-ethereum/rlp"
	"io"
	"os"
	"protocol"
	"time"
)

type Account struct {
	Index     uint64
	Name      string
	Email     string
	Phone     string
	PublicKey []byte
	Balance   uint64
	Count     uint64
	Allowance uint64
}

type AccountManager struct {
	Accounts map[uint64]*Account
	protocol.Service
	ConfigPath string
}

var (
	DefaultConfigPath = "account.config"
	AcManager         *AccountManager
	LatestCountUser   uint64
)

func NewAccountManager(path ...string) {
	AcManager = &AccountManager{
		Accounts: make(map[uint64]*Account),
		Service: protocol.Service{
			Name:        "AccountManager",
			SendPool:    nil,
			ReceivePool: make(chan protocol.Message, 100),
		},
		ConfigPath: DefaultConfigPath,
	}

	//更改配置文件路径
	if len(path) != 0 {
		AcManager.ConfigPath = path[0]
	}

	return
}

func (ac *AccountManager) GetAccountFromFile() error {
	file, err := os.OpenFile(DefaultConfigPath, os.O_RDONLY, 0666)
	if err != nil {
		return err
	}
	defer file.Close()
	//建立缓冲区，把文件内容放到缓冲区中
	buf := bufio.NewReader(file)
	for {
		//遇到\n结束读取
		b, errR := buf.ReadBytes('\n')
		if errR != nil {
			if errR == io.EOF {
				break
			}
			fmt.Println(errR.Error())
		}
		account := Account{}
		err = json.Unmarshal(b, &account)
		if err != nil {
			return err
		}
		ac.Accounts[account.Index] = &account
	}
	return nil
}
func (ac *AccountManager) SaveAccount() error {
	file, err := os.OpenFile(DefaultConfigPath, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		return err
	}
	defer file.Close()
	for i := 0; i < len(AcManager.Accounts); i++ {
		b, err := json.Marshal(*AcManager.Accounts[uint64(i)])
		if err != nil {
			return err
		}
		b = append(b, '\n')
		_, errW := file.Write(b)
		if errW != nil {
			fmt.Println(errW.Error())
			return errW
		}
	}
	return nil
}

func (ac *AccountManager) RegisterAccount(account Account) error {
	//检查账户是否冲突
	for _, value := range ac.Accounts {
		if bytes.Equal(account.PublicKey, value.PublicKey) == true {
			return errors.New("PublicKey has been register")
		}
		if account.Email == value.Email {
			return errors.New("Email has been register")
		}
		if account.Phone == value.Phone {
			return errors.New("Phone has been register")
		}
	}
	account.Index = uint64(len(ac.Accounts))
	ac.Accounts[account.Index] = &account

	LatestCountUser++
	return nil
}

func (ac *AccountManager) ChangeBalance(tx core.Transaction) error {
	//转出账户减
	for k := range ac.Accounts {
		if bytes.Equal(tx.Source, ac.Accounts[k].PublicKey) == true {
			ac.Accounts[k].Balance -= tx.Amount
			ac.Accounts[k].Balance -= tx.Gas
			ac.Accounts[k].Count++
			break
		}
	}
	//转出账户加
	for k := range ac.Accounts {
		if bytes.Equal(tx.Destination, ac.Accounts[k].PublicKey) == true {
			ac.Accounts[k].Balance += tx.Amount
			break
		}
	}

	return nil
}
func (ac *AccountManager) ReceiveMsg() {
	go func() {
		for {
			msg := <-ac.ReceivePool
			switch msg.Code {
			case protocol.RegisterAccount:
				account := &Account{}
				err := rlp.DecodeBytes(msg.Payload, account)
				if err != nil {
					fmt.Println("AC ReceiveMeg Err")
				}
				if ac.RegisterAccount(*account) != nil {
					ac.SendPool <- protocol.Message{
						protocol.RegisterAccountFail,
						msg.Size,
						msg.Payload,
						msg.Source, //通知P2PServer消息的来源，发送时替换
					}
				} else {
					ac.SendPool <- protocol.Message{
						protocol.RegisterAccountSuccess,
						msg.Size,
						msg.Payload,
						msg.Source, //通知P2PServer消息的来源，发送时替换
					}
				}

			case protocol.NewTransactionBlock:
				txblock := core.TransactionBlock{}
				err := rlp.DecodeBytes(msg.Payload, &txblock)
				if err != nil {
					fmt.Println("AC ReceiveMeg RLP DecodeBytes Err")
				}
				for i := range txblock.Trans {
					ac.ChangeBalance(txblock.Trans[i])
				}

			case protocol.TransactionChain:
				txblock := core.TransactionBlock{}
				err := rlp.DecodeBytes(msg.Payload, &txblock)
				if err != nil {
					fmt.Println("AC ReceiveMeg TransactionChain RLP DecodeBytes Err")
				}
				_, ok := core.TransactionBlockChain[txblock.Index]
				if ok == false {
					core.TransactionBlockChain[txblock.Index] = &txblock
					for i := range txblock.Trans {
						ac.ChangeBalance(txblock.Trans[i])
					}
				}

			case protocol.GetAccountNo:
				no := uint64(len(ac.Accounts))
				m := protocol.NewMessage(protocol.AccountNo, no)
				m.Source = msg.Source
				ac.SendPool <- *m
				fmt.Println("收到来自", m.Source, "的GetAccountNo")
				fmt.Println("发送给", m.Source, "AccountNo：", no)

			case protocol.AccountNo:
				var no uint64
				err := rlp.DecodeBytes(msg.Payload, &no)
				if err != nil {
					fmt.Println("protocol.AccountNo DecodeBytes err :", err)
					break
				}

				if LatestCountUser < no {
					LatestCountUser = no
					for i := uint64(len(ac.Accounts)); i < no; i++ {
						m := protocol.NewMessage(protocol.SyncAccount, i)
						m.Source = msg.Source
						ac.SendPool <- *m
						fmt.Println("发送给", m.Source, "SyncAccount:", i)
					}
				}

			case protocol.SyncAccount:
				var no uint64
				err := rlp.DecodeBytes(msg.Payload, &no)
				if err != nil {
					fmt.Println("protocol.SyncAccount DecodeBytes err :", err)
				} else {
					//发送账号信息 并将交易记录清零 接收方根据区块链进行数据更新
					temp := *ac.Accounts[no]
					temp.Count = 0
					temp.Balance = 10000
					temp.Allowance = 0

					m := protocol.NewMessage(protocol.Account, temp)
					m.Source = msg.Source
					ac.SendPool <- *m
					fmt.Println("发送给", m.Source, "Account:", no)
				}

			case protocol.Account:
				Account := Account{}
				err := rlp.DecodeBytes(msg.Payload, &Account)
				if err != nil {
					fmt.Println("protocol.Account DecodeBytes err :", err)
				} else {
					//防止重复写入
					_, ok := ac.Accounts[Account.Index]
					if ok == false {
						ac.Accounts[Account.Index] = &Account
					}
				}

			default:
				fmt.Println("AC 未知的类型")
			}
		}
	}()
}

func (ac *AccountManager) StartAcManager() {

	AcManager.GetAccountFromFile()                    //本地加载
	LatestCountUser = uint64(len(AcManager.Accounts)) //统计账户人数

	go func() {
		for {
			time.Sleep(100 * time.Microsecond)
			AcManager.SaveAccount()
		}
	}()

	go ac.ReceiveMsg()
	ac.CheckPeerAccount()
	//等待同步结束
	for {
		if LatestCountUser == uint64(len(AcManager.Accounts)) {
			break
		} else {
			time.Sleep(2 * time.Second)
		}
	}

}

func (ac *AccountManager) CheckPeerAccount() {
	msg := protocol.NewMessage(protocol.GetAccountNo, nil)
	fmt.Println(msg)
	ac.SendPool <- *msg
}

//检查交易的合法性
func CheckTransaction(tx *core.Transaction) bool {
	//查询到账户的信息
	fmt.Println("检验交易合法性")
	var src *Account
	for k := range AcManager.Accounts {
		if bytes.Equal(AcManager.Accounts[k].PublicKey, tx.Source) == true {
			src = AcManager.Accounts[k]
			break
		}
	}
	//没找到付款账户信息
	if src == nil {
		fmt.Println("没找到付款账户信息")
		return false
	}

	var des *Account
	for k := range AcManager.Accounts {
		if bytes.Equal(AcManager.Accounts[k].PublicKey, tx.Destination) == true {
			des = AcManager.Accounts[k]
			break
		}
	}
	//没找到收款账户信息
	if des == nil {
		fmt.Println("没找到收款账户信息")
		return false
	}
	//计数器错误
	if src.Count > tx.Index-1 {
		fmt.Println("计数器错误")
		return false
	}
	//余额不足
	if src.Balance < (tx.Amount + tx.Gas) {
		fmt.Println("余额不足")
		return false
	}
	//Hash不正确
	temp := *tx
	temp.Hash = []byte("")
	temp.Signature = []byte("")
	a, _ := rlp.EncodeToBytes(temp)
	hashTemp, _ := core.CalculateHash(a, core.SM3)
	if bytes.Equal(hashTemp, tx.Hash) == false {
		fmt.Println("Hash错误")
		fmt.Println("Hash:", hashTemp)
		fmt.Println("原始Hash:", tx.Hash)
		return false
	}
	//签名不正确
	pub, err := core.UnmarshalPubkey(tx.Source)
	if err != nil {
		fmt.Println("UnmarshalPubkey error")
		return false
	}
	if pub.Verify(tx.Hash, tx.Signature) == false {
		fmt.Println("签名错误")
		return false
	}

	return true
}
